//! State transition types

use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
use solana_program::{
    program_error::ProgramError,
    program_pack::{IsInitialized, Pack, Sealed},
};

/// Program states.
#[repr(C)]
#[derive(Debug, Default, PartialEq)]
pub struct UserV1 { // USDT 单币质押池
    ///
    pub is_initialized: bool,

    /// 用户质押金额
    pub amount: u64,

    /// 用户理论奖励
    pub reward_debt: u64,

}

impl UserV1 {
    /// init
    pub fn is_initialized(&self) -> bool {
        self.is_initialized
    }
}

impl Sealed for UserV1 {}
impl IsInitialized for UserV1 {
    fn is_initialized(&self) -> bool {
        true
    }
}

impl Pack for UserV1 {
    const LEN: usize = 165;

    /// Unpack from slice and check if initialized
    fn unpack(input: &[u8]) -> Result<Self, ProgramError>
        where
            Self: IsInitialized,
    {
        let value = Self::unpack_unchecked(input)?;
        if value.is_initialized() {
            Ok(value)
        } else {
            Ok(UserV1{
                is_initialized:false,
                amount:0,
                reward_debt:0,
            })
        }
    }

    /// Unpack from slice without checking if initialized
    fn unpack_unchecked(input: &[u8]) -> Result<Self, ProgramError> {
        if input.len() < Self::LEN {
            return Err(ProgramError::InvalidAccountData);
        }
        Self::unpack_from_slice(input)
    }

    fn pack_into_slice(&self, output: &mut [u8]) {
        let output = array_mut_ref![output, 0, 17];
        let (
            is_initialized,
            amount,
            reward_debt,
        ) = mut_array_refs![output, 1,8,8];
        is_initialized[0] = self.is_initialized as u8;
        *amount = self.amount.to_le_bytes();
        *reward_debt = self.reward_debt.to_le_bytes();
    }

    /// Unpacks a byte buffer into a [UserV1](struct.UserV1.html).
    fn unpack_from_slice(input: &[u8]) -> Result<Self, ProgramError> {
        let input = array_ref![input, 0, 17];
        #[allow(clippy::ptr_offset_with_cast)]
            let (
            is_initialized,
            amount,
            reward_debt,
        ) = array_refs![input,1,8,8];
        Ok(Self {
            is_initialized: match is_initialized {
                [0] => false,
                [1] => true,
                _ => false,
            },
            amount:u64::from_le_bytes(*amount),
            reward_debt:u64::from_le_bytes(*reward_debt),
        })
    }

    /// Pack into slice
    fn pack(src: Self, dst: &mut [u8]) -> Result<(), ProgramError> {
        if dst.len() <= Self::LEN {
            return Err(ProgramError::InvalidAccountData);
        }
        src.pack_into_slice(dst);
        Ok(())
    }
}